/*
 *  Licensed to the Apache Software Foundation (ASF) under one
 *  or more contributor license agreements.  See the NOTICE file
 *  distributed with this work for additional information
 *  regarding copyright ownership.  The ASF licenses this file
 *  to you under the Apache License, Version 2.0 (the
 *  "License"); you may not use this file except in compliance
 *  with the License.  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing,
 *  software distributed under the License is distributed on an
 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 *  KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations
 *  under the License.
 */
package org.apache.myfaces.test.webapp.impl;

import org.apache.myfaces.test.webapp.api.ResourceFinder;
import org.apache.myfaces.test.webapp.api.annotation.*;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * This is the manager class for all annotations present in the Test Case.
 *
 * @author Cosmin Martinconi, 28.06.2010
 */
public class AnnotationManager {

    private Class<?> testClass;

    private Configuration conf;
    private List<ConfigurationTestSuite> confTSList;
    private View view;
    private Field testerField;
    private List<Field> assertFieldList;

    public void initializeAnnotations() {
        confTSList = new ArrayList<ConfigurationTestSuite>();
        assertFieldList = new ArrayList<Field>();

        do {
            // View annotation
            View testView = testClass.getAnnotation(View.class);
            if (testView != null) {
                view = testView;
            }

            // Configuration annotation
            Configuration testConf = testClass.getAnnotation(Configuration.class);
            if (testConf != null) {
                conf = testConf;
            }

            // single Configuration Test Suite
            ConfigurationTestSuite confTS = testClass.getAnnotation(ConfigurationTestSuite.class);
            if (confTS != null) {
                confTSList.add(confTS);
            }

            // aggregated Configuration Test Suite
            ConfigurationTestSuite.List configTSList = testClass.getAnnotation(ConfigurationTestSuite.List.class);
            if (configTSList != null) {
                confTSList.addAll(Arrays.asList(configTSList.value()));
            }

            // Assertable fields and Webapp Tester annotattion
            for(Field field: testClass.getDeclaredFields()) {
                if(field.isAnnotationPresent(Assertable.class)) {
                    assertFieldList.add(field);
                }

                if(field.isAnnotationPresent(Tester.class)) {
                    if (testerField==null){
                        testerField = field;
                    }else {
                        throw new IllegalArgumentException("More then one field annotated with " + Tester.class.getName() + " found");
                    }
                }
            }

            if (testerField == null) {
                throw new IllegalArgumentException("No field annotated with " + Tester.class.getName() + " found");
            }

            if (!Modifier.isStatic(testerField.getModifiers())) {
                throw new IllegalArgumentException("Field annotated with " + Tester.class.getName() + " is not static");
            }

            if (!testerField.getType().isAssignableFrom(WebappTesterImpl.class)) {
                throw new IllegalArgumentException("Field annotated with " + Tester.class.getName() + " must be assignable from " + WebappTesterImpl.class.getName());
            }

        }
        while ((testClass = testClass.getSuperclass()) != Object.class);

    }


    public static AnnotationManager getCurrentInstance() {
        return (AnnotationManager) ResourceFinder.getResource(AnnotationManager.class.getName());
    }


    public String getBeanName(Class beanClass) {

        for (PageBean pb : getPageBeans()) {
            if (pb.clazz().equals(beanClass))
                if (pb.name().equals("")) {
                    String beanName = beanClass.getSimpleName();
                    return Character.toLowerCase(beanName.charAt(0)) + beanName.substring(1);
                } else {
                    return pb.name();
                }
        }

        throw new IllegalArgumentException("No " + beanClass.getName() + " managed bean configured!");
    }

    public Configuration getConfigurations() {
        return conf;
    }

    public List<ConfigurationTestSuite> getConfTestSuite() {
        return confTSList;
    }

    public View getView() {
        return view;
    }

    public PageBean[] getPageBeans() {
        return getView().pageBeans();
    }

    public Field getTesterField() {
        return testerField;
    }

    public List<Field> getAssertFieldList() {
        return assertFieldList;
    }

    public void setTestClass(Class<?> testClass) {
        this.testClass = testClass;
    }
}
